#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <execinfo.h>

#include "t0022-0.h"

static struct t0022_0st *t22 = NULL;
#define MODNAME	"[T22SIG]"

void segmentfault_handler(int signum) {
    void *array[10];
    size_t size;
    char **strings;

    fprintf(stderr, "Segmentation fault occurred. Printing stack trace:\n");

    size = backtrace(array, 10);
    strings = backtrace_symbols(array, size);

    if (strings == NULL) {
        perror("backtrace_symbols");
        exit(EXIT_FAILURE);
    }

    for (size_t i = 0; i < size; i++) {
        fprintf(stderr, "%s\n", strings[i]);
    }

    free(strings);
    
    exit(EXIT_FAILURE);
}

/* TODO: illegal instruction & segment fault */
static void signal_handler(int signo)
{
	int status;
	switch(signo){
		case SIGINT:
			ERRSYS_ERRPRINT("SIGINT Catched\n");
			break;
		case SIGQUIT:
			ERRSYS_ERRPRINT("SIGQUIT Catched\n");
			break;
		case SIGUSR1:
			ERRSYS_ERRPRINT("SIGUSR1 Catched\n");
			break;
		case SIGUSR2:
			ERRSYS_ERRPRINT("SIGUSR2 Catched\n");
			break;
		case SIGALRM:
			ERRSYS_ERRPRINT("SIGALRM Catched\n");
			break;
		case SIGCHLD:
			ERRSYS_ERRPRINT("SIGCHLD Catched\n");
			wait(&status);
			break;
		case SIGSEGV:
			segmentfault_handler(signo);
		default:
			break;
	}
	/* TODO: 捕捉到退出信号，通知主程序退出运行 */
	if (signo != SIGCHLD) {
		t22->flags |= T0022_0_FLAGS_MODE_QUIT;
		ERRSYS_ERRPRINT("T0022-0 set QUIT mode\n");
	}
}

int signal_initialize(struct t0022_0st *p)
{
	struct sigaction act;
	
	t22 = p;

	act.sa_handler = signal_handler;
	sigemptyset(&act.sa_mask);
	act.sa_flags = SA_RESTART | SA_SIGINFO;
	
	if (sigaction(SIGINT, &act, NULL) < 0)
		return -1;
	if (sigaction(SIGQUIT, &act, NULL) < 0)
		return -1;
	if (sigaction(SIGINT, &act, NULL) < 0)
		return -1;
	if (sigaction(SIGUSR1, &act, NULL) < 0)
		return -1;
	/* this makes el0021-0 heartbeat not work */
//	if (sigaction(SIGUSR2, &act, NULL) < 0)
//		return (int)SIG_ERR;
	if (sigaction(SIGALRM, &act, NULL) < 0)
		return -1;
	if (sigaction(SIGCHLD, &act, NULL) < 0)
		return -1;
	if (sigaction(SIGSEGV, &act, NULL) < 0)
		return -1;
	return 0;
}
